﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Utils;
using System.Windows.Input;
using System.IO;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Media;
using MoodLaZik.Model;
using ConfigDialog.Model;
using System.Windows.Data;

namespace MoodLaZik.ViewModel
{
	class MainWindow : Utils.ViewModelBase
	{
		private MoodLaZik.Model.XmlManipulator _xm;


		private Media m_selectedMedia;
		public Media SelectedMedia
		{
			get
			{
				return (m_selectedMedia);
			}
			set
			{
				if (value != m_selectedMedia)
				{
					m_selectedMedia = value;
					this.OnPropertyChanged("SelectedMedia");
				}
			}
		}
		private String m_selectedMediaPath;
		public String SelectedMediaPath { get; set; }
		private Int32 m_currentGiveStars;
		public Int32 CurrentGiveStars
		{
			get
			{
				return (m_currentGiveStars);
			}
			set
			{
				if (value != m_currentGiveStars)
				{
					m_currentGiveStars = value;
					this.OnPropertyChanged("CurrentGiveStars");
				}
			}
		}
		private bool m_mediaOpenedInit;
		private bool m_mediaIsPlaying;
		public bool MediaIsPlaying
		{
			get
			{
				return (m_mediaIsPlaying);
			}
			set
			{
				if (value != m_mediaIsPlaying)
				{
					m_mediaIsPlaying = value;
					this.OnPropertyChanged("MediaIsPlaying");
				}
			}
		}
		private bool m_mediaIsPaused;
		public bool MediaIsPaused
		{
			get
			{
				return (m_mediaIsPaused);
			}
			set
			{
				if (value != m_mediaIsPaused)
				{
					m_mediaIsPaused = value;
					this.OnPropertyChanged("MediaIsPaused");
				}
			}
		}
		private List<Media> m_playlist;
		Timer m_seekTimer;
		private Double m_currentSeekerValue;
		public Double CurrentSeekerValue
		{
			get
			{
				return (m_currentSeekerValue);
			}
			set
			{
				if (value != m_currentSeekerValue)
				{
					m_currentSeekerValue = value;
					this.OnPropertyChanged("CurrentSeekerValue");
				}
			}
		}
		private Double m_maximumSeekerValue;
		public Double MaximumSeekerValue
		{
			get
			{
				return (m_maximumSeekerValue);
			}
			set
			{
				if (value != m_maximumSeekerValue)
				{
					m_maximumSeekerValue = value;
					this.OnPropertyChanged("MaximumSeekerValue");
				}
			}
		}

		private ICommand m_playMediaCommand;
		public ICommand PlayMediaCommand
		{
			get
			{
				if (m_playMediaCommand == null)
					m_playMediaCommand = new RelayCommand<object>(this.PlayMedia, this.CanPlayMedia);
				return (m_playMediaCommand);
			}
		}

		private ICommand m_pauseMediaCommand;
		public ICommand PauseMediaCommand
		{
			get
			{
				if (m_pauseMediaCommand == null)
					m_pauseMediaCommand = new RelayCommand<object>(this.PauseMedia, this.CanPauseMedia);
				return (m_pauseMediaCommand);
			}
		}

		private ICommand m_stopMediaCommand;
		public ICommand StopMediaCommand
		{
			get
			{
				if (m_stopMediaCommand == null)
					m_stopMediaCommand = new RelayCommand<object>(this.StopMedia, this.CanStopMedia);
				return (m_stopMediaCommand);
			}
		}

		private ICommand m_prevMediaCommand;
		public ICommand PrevMediaCommand
		{
			get
			{
				if (m_prevMediaCommand == null)
					m_prevMediaCommand = new RelayCommand<object>(this.PrevMedia, this.CanPrevMedia);
				return (m_prevMediaCommand);
			}
		}

		private ICommand m_nextMediaCommand;
		public ICommand NextMediaCommand
		{
			get
			{
				if (m_nextMediaCommand == null)
					m_nextMediaCommand = new RelayCommand<object>(this.NextMedia, this.CanNextMedia);
				return (m_nextMediaCommand);
			}
		}

		private ICommand m_manageZiksCommand;
		public ICommand ManageZiksCommand
		{
			get
			{
				if (m_manageZiksCommand == null)
					m_manageZiksCommand = new RelayCommand<object>(this.ManageZiks, this.CanManageZiks);
				return (m_manageZiksCommand);
			}
		}

		private ICommand m_commandGenerate;
		public ICommand CommandGenerate
		{
			get
			{
				if (m_commandGenerate == null)
					m_commandGenerate = new RelayCommand<object>(this.Generate, this.CanGenerate);
				return (m_commandGenerate);
			}
		}

		private ICommand m_commandShowPlaylist;
		public ICommand CommandShowPlaylist
		{
			get
			{
				if (m_commandShowPlaylist == null)
					m_commandShowPlaylist = new RelayCommand<object>(this.ShowPlaylist, this.CanShowPlaylist);
				return (m_commandShowPlaylist);
			}
		}

		private ICommand m_commandRemove;
		public ICommand CommandRemove
		{
			get
			{
				if (m_commandRemove == null)
					m_commandRemove = new RelayCommand<object>(this.Remove, this.CanRemove);
				return (m_commandRemove);
			}
		}

		private String m_currentMood;
		private String m_currentPerso;
		private String m_currentPlace;
		private String m_currentEnv;
		private String m_currentWeather;
		private Int32 m_currentStars;
		public String CurrentMood
		{
			get
			{
				return (m_currentMood);
			}
			set
			{
				if (value != m_currentMood)
				{
					m_currentMood = value;
					if (m_currentMood != null) MoodLaZik.Model.XmlManipulator._infos["MOOD"] = m_currentMood;
					this.OnPropertyChanged("CurrentMood");
				}
			}
		}
		public String CurrentPerso
		{
			get
			{
				return (m_currentPerso);
			}
			set
			{
				if (value != m_currentPerso)
				{
					m_currentPerso = value;
					if (m_currentPerso != null) MoodLaZik.Model.XmlManipulator._infos["PERSONNALITY"] = m_currentPerso;
					this.OnPropertyChanged("CurrentPerso");
				}
			}
		}
		public String CurrentPlace
		{
			get
			{
				return (m_currentPlace);
			}
			set
			{
				if (value != m_currentPlace)
				{
					m_currentPlace = value;
					if (m_currentPlace != null) MoodLaZik.Model.XmlManipulator._infos["PLACE"] = m_currentPlace;
					this.OnPropertyChanged("CurrentPlace");
				}
			}
		}
		public String CurrentEnv
		{
			get
			{
				return (m_currentEnv);
			}
			set
			{
				if (value != m_currentEnv)
				{
					m_currentEnv = value;
					if (m_currentEnv != null) MoodLaZik.Model.XmlManipulator._infos["ENVIRONMENT"] = m_currentEnv;
					this.OnPropertyChanged("CurrentEnv");
				}
			}
		}
		public String CurrentWeather
		{
			get
			{
				return (m_currentWeather);
			}
			set
			{
				if (value != m_currentWeather)
				{
					m_currentWeather = value;
					if (m_currentWeather != null) MoodLaZik.Model.XmlManipulator._infos["WEATHER"] = m_currentWeather;
					this.OnPropertyChanged("CurrentWeather");
				}
			}
		}
		public Int32 CurrentStars
		{
			get
			{
				return (m_currentStars);
			}
			set
			{
				if (value != m_currentStars)
				{
					m_currentStars = value;
					this.OnPropertyChanged("CurrentStars");
				}
			}
		}

		public MainWindow()
		{
			m_selectedMedia = null;
			m_selectedMediaPath = "";
			m_mediaOpenedInit = false;
			m_mediaIsPlaying = false;
			m_mediaIsPaused = false;
			m_seekTimer = new Timer();
			m_seekTimer.Tick += new EventHandler(TimerEventProcessor);
			m_seekTimer.Interval = 1000;
			m_currentSeekerValue = 0;
			m_maximumSeekerValue = 1;
			m_playlist = new List<Media>();
			MoodLaZik.Model.XmlManipulator._infos = new Dictionary<string, string>();
			this._xm = new Model.XmlManipulator();
		}

		private void TimerEventProcessor(Object myObject, EventArgs myEventArgs)
		{
			if (m_mediaIsPlaying == true)
				CurrentSeekerValue++;
			//if (CurrentSeekerValue >= MaximumSeekerValue)
			//	this.media_MediaEnded(null, null);
		}

		public bool CanPlayMedia(object _parameter)
		{
			return (m_selectedMediaPath != "" && !m_mediaIsPlaying);
		}
		public void PlayMedia(object _parameter)
		{
			MediaElement media;

			if (_parameter is MediaElement)
				media = _parameter as MediaElement;
			else
				return;

			if (m_mediaOpenedInit == false)
			{
				media.MediaOpened += new RoutedEventHandler(media_MediaOpened);
				media.MediaEnded += new RoutedEventHandler(media_MediaEnded);
				media.MediaFailed += new EventHandler<ExceptionRoutedEventArgs>(media_MediaFailed);
				m_mediaOpenedInit = true;
			}

			if (m_mediaIsPlaying == false && m_mediaIsPaused == false)
			{
				if (!m_mediaIsPaused)
				{
					try
					{
						m_selectedMediaPath = m_selectedMedia.Path;
						this.OnPropertyChanged("SelectedMedia");
						media.LoadedBehavior = MediaState.Manual;
						media.UnloadedBehavior = MediaState.Manual;
						media.Source = new Uri(m_selectedMediaPath, UriKind.RelativeOrAbsolute);
						media.Play();
						m_seekTimer.Stop();
					}
					catch (Exception e)
					{
						System.Windows.Forms.MessageBox.Show("Error: Cannot play the file: " + m_selectedMediaPath + ": " + e.Message);
						return;
					}
				}
				else
				{
					System.Windows.Forms.MessageBox.Show("Cannot open " + m_selectedMediaPath);
					return;
				}
			}
			else
			{
				media.Play();
				m_seekTimer.Start();
			}

			MediaIsPlaying = true;
			MediaIsPaused = false;
		}

		public void media_MediaEnded(object sender, RoutedEventArgs e)
		{
			//m_selectedMediaPath = "";
			(sender as MediaElement).Stop();
			m_seekTimer.Stop();
			CurrentSeekerValue = 0;
			MediaIsPlaying = false;
			MediaIsPaused = false;
		}
		public void media_MediaOpened(object sender, RoutedEventArgs e)
		{
			MediaElement mediaElement = sender as MediaElement;
			if (mediaElement == null)
				return;
			//var tl = new MediaTimeline(mediaElement.Source);
			//mediaElement.Clock = tl.CreateClock(true) as MediaClock;
			if (mediaElement.NaturalDuration.HasTimeSpan)
			{
				MaximumSeekerValue = mediaElement.NaturalDuration.TimeSpan.TotalSeconds;
				m_seekTimer.Start();
			}
		}

		public void media_MediaFailed(object sender, RoutedEventArgs e)
		{
			System.Windows.MessageBox.Show("Error: The media player can't read the file: " + (sender as MediaElement).Source.AbsolutePath);
		}

		public bool CanPauseMedia(object _parameter)
		{
			return (m_mediaIsPlaying && !m_mediaIsPaused);
		}
		public void PauseMedia(object _parameter)
		{
			MediaElement mediaElement;
			if (_parameter is MediaElement)
				mediaElement = _parameter as MediaElement;
			else
				return;

			mediaElement.Pause();
			m_seekTimer.Stop();

			MediaIsPlaying = false;
			MediaIsPaused = true;
		}

		public bool CanStopMedia(object _parameter)
		{
			return (m_selectedMediaPath != "" && (m_mediaIsPlaying == true || m_mediaIsPaused == true));
		}
		public void StopMedia(object _parameter)
		{
			MediaElement mediaElement;
			if (_parameter is MediaElement)
				mediaElement = _parameter as MediaElement;
			else
				return;

			mediaElement.LoadedBehavior = MediaState.Manual;
			mediaElement.UnloadedBehavior = MediaState.Manual;
			mediaElement.Stop();
			m_seekTimer.Stop();
			CurrentSeekerValue = 0;

			MediaIsPlaying = false;
			MediaIsPaused = false;
		}

		public bool CanPrevMedia(object _parameter)
		{
			return (m_playlist != null && m_playlist.Count > 1 && m_selectedMedia != null);
		}
		public void PrevMedia(object _parameter)
		{
			this.StopMedia(_parameter);
			Int32 index = m_playlist.IndexOf(m_selectedMedia) - 1;
			if (index <= 0)
				index = m_playlist.Count - 1;
			m_selectedMedia = m_playlist.ElementAt(index);
			this.PlayMedia(_parameter);
		}

		public bool CanNextMedia(object _parameter)
		{
			return (m_playlist != null && m_playlist.Count > 1 && m_selectedMedia != null);
		}
		public void NextMedia(object _parameter)
		{
			this.StopMedia(_parameter);
			Int32 index = m_playlist.IndexOf(m_selectedMedia) + 1;
			if (index >= m_playlist.Count)
				index = 0;
			m_selectedMedia = m_playlist.ElementAt(index);
			this.PlayMedia(_parameter);
		}

		public bool CanManageZiks(object _parameter)
		{
			return (true);
		}
		public void ManageZiks(object _parameter)
		{
			System.AppDomain NewAppDomain = System.AppDomain.CreateDomain("NewApplicationDomain");
			NewAppDomain.ExecuteAssembly(@"ConfigDialog.exe");
		}

		public bool CanGenerate(object _parameter)
		{
			return (true);
		}
		public void Generate(object _parameter)
		{
			var list = Agent.Agent.Generate(new Config
			{
				Env = CurrentEnv,
				Mood = CurrentMood,
				Personnality = CurrentPerso,
				Place = CurrentPlace,
				Stars = CurrentStars,
				Weather = CurrentWeather
			}, _xm);
			if (list != null && list.Count > 0)
			{
				this.StopMedia(_parameter);
				m_playlist = list;
				m_selectedMedia = list.ElementAt(0);
				m_selectedMediaPath = m_selectedMedia.Path;
				this.PlayMedia(_parameter);
			}
			else
				System.Windows.Forms.MessageBox.Show("Error: Cannot generate playlist. (Did you ever add a music?)");
		}

		public bool CanShowPlaylist(object _parameter)
		{
			return (true);
		}
		public void ShowPlaylist(object _parameter)
		{
			String s = "";
			if (m_playlist.Count > 0)
			{
				foreach (Media m in m_playlist)
					s += "\n" + m.Name;
			}
			else
				s += "NONE";
			System.Windows.Forms.MessageBox.Show(s);
		}

		public bool CanRemove(object _parameter)
		{
			return (m_selectedMedia != null);
		}

		public void Remove(object _parameter)
		{
			Media m = m_selectedMedia;
			if ((m_playlist.Contains(m)))
			{
				m_playlist.Remove(m);
				this._xm.RemoveSongtitleFromAgentBrain(Model.XmlManipulator._infos, m.Path);
				this.NextMedia(_parameter);
			}
		}
	}

	public class MediaToNameConverter : IValueConverter
	{
		#region IValueConverter Members

		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			var media = value as Media;
			if (media != null)
				return (media.Name);
			return ("");
		}

		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			return (null);
		}

		#endregion
	}

	public class BoolToVisibilityConverter : IValueConverter
	{
		#region IValueConverter Members

		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			return (((bool)value == true) ? Visibility.Visible : Visibility.Hidden);
		}

		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			return (null);
		}

		#endregion
	}

	public class BoolNotToVisibilityConverter : IValueConverter
	{
		#region IValueConverter Members

		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			return (((bool)value == false) ? Visibility.Visible : Visibility.Hidden);
		}

		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			return (null);
		}

		#endregion
	}
}
